package by.yativem.commons.task;

import java.security.InvalidParameterException;
import java.util.HashMap;
import java.util.Map;
import java.util.PriorityQueue;

import org.apache.log4j.Logger;

import by.yativem.commons.thread.ThreadPool;
import by.yativem.commons.utils.string.StringUtil;

public class TasksEngine implements Runnable {

	protected static class TaskWrapper implements Comparable<TaskWrapper> {
		protected int priority;
		protected AbstractTask task;
		

		public TaskWrapper(int priority, AbstractTask task) {
			this.priority = priority;
			this.task = task;
		}

		@Override
		public int compareTo(TaskWrapper o) {
			return this.priority - o.priority;
		}

	}
	
	private static final Logger log = Logger.getLogger(TasksEngine.class);
	private int defaultThreadCount = 10;
	private final Object lock = new Object();
	private static long taskIdcounter = 0;
	private int threadPoolCount = 3;

	/*
	 * represent map of tasks. key: taskId
	 */
	private Map<Long, AbstractTask> tasks;
	private PriorityQueue<TaskWrapper> taskQueue;
	private ThreadGroup threadGroup;
	private ThreadPool threadPool;

	// private PriorityQueue<TaskWrapper> taskQueue = null;

	public void processTask(int priority, AbstractTask task) {
		synchronized (lock) {

			if (task.getTaskId() > 0) {
				throw new IllegalStateException(
						"The task id shuldbe uninitialized");
			}
			task.setTaskId(generateNextIdCounter());
			tasks.put(task.getTaskId(), task);
			TaskWrapper tw = new TaskWrapper(priority, task);
			taskQueue.offer(tw);
		}
		synchronized (lock) {
			lock.notifyAll();
		}
		

	}

	public TasksEngine(int threadsCount) {
		this();
		this.threadPoolCount = threadsCount;
		threadPool = new ThreadPool(threadPoolCount);
	}

	public TasksEngine() {
		taskQueue = new PriorityQueue<TaskWrapper>();
		threadGroup = new ThreadGroup("Task Engine Workers");
		tasks = new HashMap<Long, AbstractTask>();
		threadPool = new ThreadPool(defaultThreadCount);
		// threads = new ArrayList<Thread>(threadPoolCount);
	}

	@Override
	public void run() {
		Thread.currentThread().setName("Task Engine");
		log.info("Task Engine is started");
		
		while (true) {
			try {

				synchronized (lock) {
					if (!taskQueue.isEmpty() && threadPool.hasAvaliableWorker()) {
						TaskWrapper tw = taskQueue.poll();
						threadPool.processThread(tw.task);
					}
					
					lock.wait(10000);
				}

				

			} catch (Exception e) {
				log.error("", e);
			}

		}
	}

	protected synchronized long generateNextIdCounter() {
		taskIdcounter++;
		return taskIdcounter;
	}
	
	public synchronized AbstractManagedTask getManagedTask(Long id){
		return (AbstractManagedTask) tasks.get(id);
	}
	
	public synchronized AbstractManagedTask getManagedTask(String taskName){
		
		if(StringUtil.isBlank( taskName )){
			
			throw new InvalidParameterException();
		}
		
		for(AbstractTask task : tasks.values()){
			if ( taskName.equals( task.getTaskName()) ){
				return (AbstractManagedTask) task;
			}
		}
		throw new InvalidParameterException("No task in task engine found. Task Name +" + taskName  );
	}


}
